﻿using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using ZeroSum.DependencyInjection.Attributes;
using ZeroSum.Extensions;
using ZeroSum.Helpers;

namespace ZeroSum.DependencyInjection.Extensions;

public static class DependencyInjectionExtensions
{
    /// <summary>
    ///     默认的声明周期
    /// </summary>
    private static ServiceLifetime defaultLifetime;

    /// <summary>
    ///     添加自动依赖注入
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="lifetime">默认的生命周期</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddDependencyInjection(this IServiceCollection services,
        ServiceLifetime lifetime = ServiceLifetime.Transient)
    {
        defaultLifetime = lifetime;
        var assemblies = new List<Assembly>();
        assemblies.AddRange(AssemblyHelper.GetProjectAssemblies());
        assemblies.AddRange(AssemblyHelper.GetPackageAssemblies(nameof(ZeroSum)));
        Type[] baseTypes = {typeof(ISingletonDependency), typeof(IScopeDependency), typeof(ITransientDependency)};
        var dependencies = assemblies.SelectMany(m => m.GetTypes()).Where(type => type.IsClass && !type.IsAbstract
            && !type.IsInterface && !type.HasAttribute<IgnoreDependencyAttribute>()
            && (baseTypes.Any(b => b.IsAssignableFrom(type)) || type.HasAttribute<RegisterAttribute>())).ToArray();
        foreach (var dependency in dependencies) AddToServices(services, dependency, baseTypes);

        return services;
    }

    /// <summary>
    ///     将服务实现类型注册到服务集合中
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="implementationType">要注册的服务实现类型</param>
    /// <param name="baseTypes"></param>
    private static void AddToServices(IServiceCollection services, Type implementationType, Type[] baseTypes)
    {
        var lifetime = GetLifetime(implementationType)!;
        var serviceTypes = implementationType.GetInterfaces()
            .Where(x => !baseTypes.Contains(x) && !implementationType.IsGenericType && !x.IsGenericType
                        || implementationType.IsGenericType && x.IsGenericType
                                                            && implementationType.GetGenericArguments().Length ==
                                                            x.GetGenericArguments().Length).ToArray();

        //服务数量为0时注册自身
        if (serviceTypes.Length == 0)
        {
            services.Add(new ServiceDescriptor(implementationType, implementationType, lifetime.Value));
            return;
        }

        //注册服务
        foreach (var serviceType in serviceTypes)
            services.Add(new ServiceDescriptor(serviceType, implementationType, lifetime.Value));
    }

    /// <summary>
    ///     重写以实现 从类型获取要注册的<see cref="ServiceLifetime" />生命周期类型
    /// </summary>
    /// <param name="type">类型</param>
    /// <returns>生命周期类型</returns>
    private static ServiceLifetime? GetLifetime(Type type)
    {
        if (type.IsDeriveClassFrom<ITransientDependency>()) return ServiceLifetime.Transient;

        if (type.IsDeriveClassFrom<IScopeDependency>()) return ServiceLifetime.Scoped;

        if (type.IsDeriveClassFrom<ISingletonDependency>()) return ServiceLifetime.Singleton;

        var attribute = type.GetAttribute<RegisterAttribute>();

        if (attribute == null) return defaultLifetime;

        return attribute.Lifetime ?? defaultLifetime;
    }
}